﻿using System;
using System.Collections.Generic;
using log4net;


namespace Web7.Logging
{
	public class Web7Log4netFactory : LoggerFactory
	{
		/// <summary>
		/// 生成一个针对指定类型的日志记录工具
		/// </summary>
		/// <param name="type">类型</param>
		/// <returns></returns>
		public override ILogger CreateLogger(Type type)
		{
			var logger = LogManager.GetLogger(type);
			
			if(null == loggers)
			{
				loggers = new List<Web7Log4netLogger>();
			}


			var we7Logger = loggers.Find(item => item.Log4InnerLogger == logger);
			if(null == we7Logger)
			{
				we7Logger = new Web7Log4netLogger(logger);
				loggers.Add(we7Logger);
			}

			return we7Logger;
		}

		private static List<Web7Log4netLogger> loggers;
	}

	public class Web7Log4netLogger : ILogger
	{
		public Web7Log4netLogger(ILog innerLogger)
		{
			Log4InnerLogger = innerLogger;
		}

		internal ILog Log4InnerLogger { get; private set; }

		#region 私有辅助方法（获取代理的方法）

		private Action<string> EnabledWrapperedProcess_MessageOnly(Action<string> org, OperationProcessLevel level)
		{
			if (IsEnabled(level))
			{
				return org;
			}
			else
			{
				// 空方法
				return (item => { });
			}
		}

		private Action<string, Exception> EnabledWrapperedProcess_MessageException(Action<string, Exception> org, OperationProcessLevel level)
		{
			if (IsEnabled(level))
			{
				return org;
			}
			else
			{
				// 空方法
				return ((item, ex) => { });
			}
		}

		private Action<string> GetMessageOnlyProceser(OperationProcessLevel level)
		{
			Action<string> action;
			switch (level)
			{
				case OperationProcessLevel.Fatal:
					action = Log4InnerLogger.Fatal;
					break;
				case OperationProcessLevel.Error:
					action = Log4InnerLogger.Error;
					break;
				case OperationProcessLevel.Debug:
					action = Log4InnerLogger.Debug;
					break;
				case OperationProcessLevel.Warning:
					action = Log4InnerLogger.Warn;
					break;

				default:
				case OperationProcessLevel.Infomation:
					action = Log4InnerLogger.Info;
					break;
			}
			return EnabledWrapperedProcess_MessageOnly(action, level);
		}

		private Action<string, Exception> GetMessageExceptionProceser(OperationProcessLevel level)
		{
			Action<string, Exception> action;
			switch (level)
			{
				case OperationProcessLevel.Fatal:
					action = Log4InnerLogger.Fatal;
					break;
				case OperationProcessLevel.Error:
					action = Log4InnerLogger.Error;
					break;
				case OperationProcessLevel.Debug:
					action = Log4InnerLogger.Debug;
					break;
				case OperationProcessLevel.Warning:
					action = Log4InnerLogger.Warn;
					break;

				default:
				case OperationProcessLevel.Infomation:
					action = Log4InnerLogger.Info;
					break;
			}

			return EnabledWrapperedProcess_MessageException(action, level);
		}

		#endregion

		public bool IsEnabled(OperationProcessLevel level)
		{
			switch(level)
			{
				case OperationProcessLevel.Fatal:
					return Log4InnerLogger.IsFatalEnabled;
				case OperationProcessLevel.Error:
					return Log4InnerLogger.IsErrorEnabled;
				case OperationProcessLevel.Debug:
					return Log4InnerLogger.IsDebugEnabled;
				case OperationProcessLevel.Warning:
					return Log4InnerLogger.IsWarnEnabled;

				default:
				case OperationProcessLevel.Infomation:
					return Log4InnerLogger.IsInfoEnabled;
			}
		}

		public void Log(Exception exception)
		{
			Log(exception, exception.GetLevel());
		}

		public void Log(Exception exception, OperationProcessLevel level)
		{
			GetMessageExceptionProceser(level).Invoke(exception.Message, exception);
		}

		public void Log(string message, Exception exception, OperationProcessLevel level)
		{
			GetMessageExceptionProceser(level).Invoke(message, exception);
		}

		public void Log(string message)
		{
			Log(message, OperationProcessLevel.Infomation);
		}

		public void Log(string message, OperationProcessLevel level)
		{
			GetMessageOnlyProceser(level).Invoke(message);
		}

		public void LogFormat(string format, params object[] args)
		{
			LogFormat(OperationProcessLevel.Infomation, format, args);
		}

		public void LogFormat(OperationProcessLevel level, string format, params object[] args)
		{
			if(!IsEnabled(level))
			{
				return;
			}

			switch (level)
			{
				case OperationProcessLevel.Fatal:
					Log4InnerLogger.FatalFormat(format, args);
					break;
				case OperationProcessLevel.Error:
					Log4InnerLogger.ErrorFormat(format, args);
					break;
				case OperationProcessLevel.Debug:
					Log4InnerLogger.DebugFormat(format, args);
					break;
				case OperationProcessLevel.Warning:
					Log4InnerLogger.FatalFormat(format, args);
					break;

				default:
				case OperationProcessLevel.Infomation:
					Log4InnerLogger.InfoFormat(format, args);
					break;
			}
		}
	}
}
